// Copyright 2019 orivil.com. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found at https://mit-license.org.

package container

import (
	"encoding/json"
	"gitee.com/tugoer/psys/models"
	"gitee.com/tugoer/psys/utils"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"sync"
)

var resultDir = "data/result"

func init() {
	err := os.MkdirAll(resultDir, os.ModePerm)
	if err != nil {
		panic(err)
	}
}

func readResultData(id, options string) (data []byte, err error) {
	file, _ := resultFile(id, options, false)
	return ioutil.ReadFile(file)
}

func writeResultData(id, options string, data []byte) error {
	file, err := resultFile(id, options, true)
	if err != nil {
		return err
	}
	return ioutil.WriteFile(file, data, os.ModePerm)
}

func removeResultData(id string) (err error) {
	dir := filepath.Join(resultDir, id)
	return os.RemoveAll(dir)
}

func resultFile(id, options string, mkDir bool) (string, error) {
	dir := filepath.Join(resultDir, id)
	if mkDir {
		err := os.MkdirAll(dir, os.ModePerm)
		if err != nil {
			return "", err
		}
	}
	return filepath.Join(dir, options+".json"), nil
}

var Result = &result{data: make(map[string]*models.Result, 10)}

type result struct {
	data map[string]*models.Result
	mu   sync.RWMutex
}

func (ec *result) key(id, options string) string {
	return id + "-" + options
}

func (ec *result) Flash(id string) error {
	ec.mu.Lock()
	defer ec.mu.Unlock()
	for key := range ec.data {
		if strings.HasPrefix(key, id) {
			delete(ec.data, key)
		}
	}
	return removeResultData(id)
}

func (ec *result) Get(id, options, acid, ext string) (result *models.Result, err error) {
	ec.mu.Lock()
	defer ec.mu.Unlock()
	key := ec.key(id, options)
	result = ec.data[key]
	if result == nil {
		// 本地获取数据
		data, err := readResultData(id, options)
		if err != nil {
			if os.IsNotExist(err) {
				// 拉取远程数据
				data, err := utils.GetGameResult(id, options, acid, ext)
				if err != nil {
					return nil, err
				} else {
					result = &models.Result{}
					err = models.UnmarshalResult(result, data)
					if err != nil {
						return nil, err
					}
					// 保存远程数据
					data, err := json.Marshal(result)
					if err != nil {
						return nil, err
					}
					err = writeResultData(id, options, data)
					if err != nil {
						return nil, err
					}
				}
			} else {
				return nil, err
			}
		} else {
			// 解析本地数据
			result = &models.Result{}
			err = json.Unmarshal(data, result)
			if err != nil {
				return nil, err
			}
		}
		ec.data[key] = result
	}
	return result, nil
}
